import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';
import 'package:nertc_core/nertc_core.dart';
import 'package:nim_core/nim_core.dart';

import '../model/user_model.dart';
import '../network/whl_api.dart';
import '../pages/whl_chat/whl_chat_room/whl_chat_room_logic.dart';
import '../routes/whl_app_pages.dart';
import '../utils/event_bus_utils.dart';
import 'chat_manager.dart';

String imAppKey = "4e29938c70eacc6b0119f65e17555cf5";

String imAutoAccountKey = "imAutoAccountKey";
String imAutoTokenKey = "imAutoTokenKey";

typedef BoolCallBack = Function(bool result);

class ChatRTCManager
    with NERtcVideoRendererEventListener, NERtcChannelEventCallback {
  static ChatRTCManager? _instance;

  final NERtcEngine _engine = NERtcEngine.instance;
  List<RtcUserSession> remoteSessions = [];
  RtcUserSession? _localSession;

  bool isSpeakerEnabled = false;
  bool isAudioEnabled = false;
  bool isLeaveChannel = false;
  bool isVideoEnabled = true;
  bool isFrontCameraMirror = true;
  bool isFrontCamera = true;

  bool? isVideoCall;

  int myUid = 0;

  bool isCallIng = false;

  int callTime = 0;
  String toAccountId = "";

  UserModel? userModel;

  static ChatRTCManager getInstance() {
    _instance ??= ChatRTCManager._internal();
    return _instance!;
  }

  ChatRTCManager._internal();

  void _releaseRtcEngine() async {
    await _engine.release();
  }

  void stopCall() {
    // if (_localSession == null) {
    //   return;
    // }
    userModel = null;
    _leaveChannel();
    _releaseRtcEngine();
  }

  void _leaveChannel() async {
    isCallIng = false;
    await _engine.enableLocalVideo(false);
    await _engine.enableLocalAudio(false);
    await _engine.stopVideoPreview();
    _localSession = null;
    remoteSessions.clear();
    toAccountId = "";
    isSpeakerEnabled = false;
    isAudioEnabled = false;
    isLeaveChannel = false;
    isVideoEnabled = true;
    isFrontCameraMirror = true;
    isFrontCamera = true;
    isVideoCall = false;
    myUid = 0;
    callTime = 0;
    await _engine.leaveChannel();
  }

  void initRtc(String token, String roomName, int uid,
      {bool isVideo = false}) async {
    // NERtcOptions options = NERtcOptions();
    myUid = uid;
    // isAudioEnabled = true;
    isVideoEnabled = isVideo;
    isVideoCall = isVideo;
    _engine
        .create(
            appKey: ChatManager.getInstance().getImAppKey(),
            channelEventCallback: this)
        .then((value) => _engine.setEventCallback(this))
        .then((value) => _engine.enableLocalAudio(true))
        .then((value) => _engine.enableLocalVideo(isVideo))
        .then((value) => _initRenderer())
        .then((value) => openCloseSpeakerphone(isSpeakerEnabled))
        .then((value) => _engine.joinChannel(token, roomName, uid));
    if (isVideo) {
      _engine.startVideoPreview();
    }
  }

  Future<void> _initRenderer() async {
    isCallIng = true;
    _localSession = RtcUserSession(myUid);
    remoteSessions.add(_localSession!);
    updateLocalMirror();

    RtcStatus rtcStatus = RtcStatus(0, remoteSessions);
    EventBusUtils.getInstance().eventBus.fire(rtcStatus);
  }

  void updateLocalMirror() {
    _localSession?.mirror.value = isFrontCamera && isFrontCameraMirror;
  }

  switchCamera({BoolCallBack? callBack}) {
    _engine.deviceManager.switchCamera().then((value) {
      if (value == 0) {
        isFrontCamera = !isFrontCamera;
        updateLocalMirror();
        if (callBack != null) {
          callBack(isFrontCamera);
        }
      }
    });
  }

  openCloseCamera(bool videoEnabled, {BoolCallBack? callBack}) {
    _engine.enableLocalVideo(videoEnabled).then((value) {
      if (value == 0) {
        isVideoEnabled = videoEnabled;
        if (callBack != null) {
          callBack(isVideoEnabled);
        }
      }
    });
  }

  openCloseAudio(bool audioEnabled, {BoolCallBack? callBack}) {
    _engine.muteLocalAudioStream(audioEnabled).then((value) {
      if (value == 0) {
        isAudioEnabled = audioEnabled;
        if (callBack != null) {
          callBack(isAudioEnabled);
        }
      }
    });
  }

  openCloseSpeakerphone(bool speakerEnabled, {BoolCallBack? callBack}) {
    _engine.deviceManager.setSpeakerphoneOn(speakerEnabled).then((value) {
      if (value == 0) {
        isSpeakerEnabled = speakerEnabled;
        if (callBack != null) {
          callBack(isSpeakerEnabled);
        }
      }
    });
  }

  @override
  void onUserJoined(int uid, NERtcUserJoinExtraInfo? joinExtraInfo) {
    final session = RtcUserSession(uid, false);
    remoteSessions.add(session);
    callTime = 0;
    print("join start 66666");
    RtcStatus rtcStatus = RtcStatus(1, remoteSessions);
    EventBusUtils.getInstance().eventBus.fire(rtcStatus);
  }

  @override
  void onUserLeave(
      int uid, int reason, NERtcUserLeaveExtraInfo? leaveExtraInfo) {
    // for (RtcUserSession session in remoteSessions.toList()) {
    //   if (session.uid == uid) {
    //     _remoteSessions.remove(session);
    //   }
    // }
    // setState(() {});

    //挂断
    remoteSessions.clear();
    RtcStatus rtcStatus = RtcStatus(-1, remoteSessions);
    EventBusUtils.getInstance().eventBus.fire(rtcStatus);

    stopCall();
  }

  @override
  void onUserVideoStart(int uid, int maxProfile) {
    setupVideoView(uid, maxProfile, false);
  }

  Future<void> setupVideoView(int uid, int maxProfile, bool subStream) async {
    _engine.subscribeRemoteVideoStream(
        uid, NERtcRemoteVideoStreamType.high, true);
    // setState(() {});
  }

  Future<void> releaseVideoView(int uid, bool subStream) async {
    _engine.subscribeRemoteSubStreamVideo(uid, false);
  }

  @override
  void onUserVideoStop(int uid) {
    releaseVideoView(uid, false);
  }

  @override
  void onFirstFrameRendered(int uid) {
    // TODO: implement onFirstFrameRendered
  }

  @override
  void onFrameResolutionChanged(int uid, int width, int height, int rotation) {
    // TODO: implement onFrameResolutionChanged
  }
}

class RtcUserSession {
  final int uid;
  final bool subStream;

  RtcUserSession(this.uid, [this.subStream = false]);

  ValueNotifier<bool>? _mirror;

  ValueNotifier<bool> get mirror {
    _mirror ??= ValueNotifier<bool>(false);
    return _mirror!;
  }
}

class RtcStatus {
  int? status; //0 拨号中 1 通话中 -1 挂断
  List<RtcUserSession> remoteSessions = [];

  RtcStatus(this.status, this.remoteSessions);
}

getRTCToken(String channelName,
    {String? toAccountId, bool isVideoCall = false, bool isReceive = false,UserModel? userModel}) {
  WhlApi.getRTCToken.get({"channelName": channelName}).then((value) async {
    if (value.isSuccess()) {
      Map a = value.data;
      a["isVideoCall"] = isVideoCall;
      a["uid"] = int.parse(value.data["uid"]);
      a["isCall"] = !isReceive;
      a["toAccountId"] = toAccountId;
      a["userModel"] = userModel;
      Get.toNamed(Routes.chatCallIngPage, arguments: a);
      print("get token success");
      print(a);
      if (!isReceive) {
        sendCallMessage(channelName,
            toAccountId: toAccountId, isVideoCall: isVideoCall);
      }
    }
  });
}

sendCallMessage(String channelName,
    {String? toAccountId, bool isVideoCall = false}) async {
  NIMCustomMessageAttachment? attachment = NIMCustomMessageAttachment.fromMap({
    "channelName": channelName,
    "customType":
        isVideoCall ? MyCustomMsgType.videoCall.tag : MyCustomMsgType.audioCall.tag
  });
  NIMResult<NIMMessage> result = await MessageBuilder.createCustomMessage(
      sessionId: toAccountId ?? "",
      sessionType: NIMSessionType.p2p,
      attachment: attachment);
  NIMMessage? message = result.data;
  ChatManager.getInstance().sendMessageToIM(message: message!);

  WhlChatRoomLogic? chatLogic = Get.find<WhlChatRoomLogic>();
  if (chatLogic != null) {
    print("refresh 111111");
    chatLogic.messageList.insert(0, message);
  }
}

sendCallJTNotification(String toAccountId) {
  CustomNotification notification = CustomNotification(
      sessionId: toAccountId, sessionType: NIMSessionType.p2p, content: "1");

  NimCore.instance.systemMessageService.sendCustomNotification(notification);
}

sendCallCancelMessage(
    {String? toAccountId,
    bool isVideoCall = false,
    bool isReceive = false}) async {

  NIMCustomMessageAttachment? attachment =
      NIMCustomMessageAttachment.fromMap({"isReceive": isReceive,"customType":
      isVideoCall ? MyCustomMsgType.videoCall.tag : MyCustomMsgType.audioCall.tag,"actionType":-1});
  NIMResult<NIMMessage> result = await MessageBuilder.createCustomMessage(
      sessionId: toAccountId ?? "",
      sessionType: NIMSessionType.p2p,
      attachment: attachment);
  NIMMessage? message = result.data;
  ChatManager.getInstance().sendMessageToIM(message: message!);
  WhlChatRoomLogic? chatLogic = Get.find<WhlChatRoomLogic>();
  if (chatLogic != null) {
    chatLogic.messageList.insert(0, message);
  }
}

sendCallGDMessage(
    {String? toAccountId, bool isVideoCall = false, int callTime = 0}) async {
  NIMCustomMessageAttachment? attachment =
      NIMCustomMessageAttachment.fromMap({"callTime": callTime,"customType":
      isVideoCall ? MyCustomMsgType.videoCall.tag : MyCustomMsgType.audioCall.tag,"actionType":-1});
  NIMResult<NIMMessage> result = await MessageBuilder.createCustomMessage(
      sessionId: toAccountId ?? "",
      sessionType: NIMSessionType.p2p,
      attachment: attachment);
  NIMMessage? message = result.data;
  ChatManager.getInstance().sendMessageToIM(message: message!);
  WhlChatRoomLogic? chatLogic = Get.find<WhlChatRoomLogic>();
  if (chatLogic != null) {
    chatLogic.messageList.insert(0, message);
  }
}
